#include <stdio.h>

#include "tknetbusi.h"
#include "constants.h"
#include "tkerror.h"
#include "tklog.h"
#include "tkevent.h"

struct tk_connect* get_tk_connect(struct custom_socket *s)
{
	struct tk_connect *conn = (struct tk_connect*)malloc(sizeof(struct tk_connect));
	if (!conn)	
		return NULL;

	memset(conn, 0x00, sizeof(struct tk_connect));
	conn->csock = s;
	if (!conn->csock) {
		free(conn);
		return NULL;
	}

	s->conn_ptr = (void*)conn;	
	
	return conn;
}

void destory_tk_connect(struct epoll_env *env, struct tk_connect *conn)
{
	if (conn == NULL)
		return;

	if (conn->csock)
		destory_custom_socket(env, conn->csock);
	conn->csock->conn_ptr = NULL;
	conn->csock = NULL;

	free(conn);		
}

int init_tk_message(struct tk_message *msg, char *body, int body_len, int type)
{
	if (body_len > MAXMESSAGELEN)
		return TK_TOO_LONG_MESSAGE; 

	msg->header_left_len = HEADERLEN;
	msg->header[HEADERLEN] = '\0';
	sprintf(msg->header, "%04d%04d", type, body_len);
	msg->message_type = type;
	msg->body_len = body_len;
	msg->body_left_len = body_len;
	memcpy(msg->body, body, body_len);
	msg->body[body_len] = '\0';

	return TK_OK;
}

int set_tk_message_header(struct tk_message *msg, int body_len, int type)
{
        if (body_len > MAXMESSAGELEN)
                return TK_TOO_LONG_MESSAGE;

        msg->header_left_len = HEADERLEN;
        msg->header[HEADERLEN] = '\0';
        sprintf(msg->header, "%04d%04d", type, body_len);
        msg->message_type = type;
        msg->body[body_len] = '\0';

        return TK_OK;
}

void tk_recv_head_init(struct custom_socket *s)
{
	struct tk_connect *conn = (struct tk_connect*)s->conn_ptr;
	/* need to recv head len, not represent aready having buf len */

	memset(&conn->recv_msg, 0x00, sizeof(conn->recv_msg));
	conn->recv_msg.header_left_len = HEADERLEN;
	conn->recving_head = 1;
	conn->recving_body = 0;
}

void tk_send_head_init(struct custom_socket *s)
{
        struct tk_connect *conn = (struct tk_connect*)s->conn_ptr;

	conn->recv_msg.header_left_len = HEADERLEN;
	conn->sending_head = 1;
	conn->sending_body = 0;
}

/* @RETURN:        1. TK_OK 2. TK_AGAIN 3. TK_ERROR 4. TK_DONE	(remote close)	*/
int tk_recv_head(struct custom_socket *s)
{
        int r = 0;
        struct tk_connect *conn = (struct tk_connect*)s->conn_ptr;
        struct tk_message *msg = &conn->recv_msg;
        int need_recv_len = msg->header_left_len;
        int aready_recv_len = HEADERLEN - msg->header_left_len;

        if (need_recv_len == 0)
                return TK_OK;

        r = tk_recvn(s->sockfd, msg->header + aready_recv_len, &need_recv_len);
        conn->recv_msg.header_left_len -= need_recv_len;

        return r;
}

/* @RETURN:        1. TK_AGAIN 2. TK_ERROR(errno) *3. TK_DONE(no use)* 4. TK_OK	*/
int tk_send_head(struct custom_socket *s)
{
        int r = 0;
        struct tk_connect *conn = (struct tk_connect*)s->conn_ptr;
        struct tk_message *msg = &conn->send_msg[conn->msg_start];
        int need_send_len = msg->header_left_len;
        int aready_send_len = HEADERLEN - msg->header_left_len;

        if (need_send_len == 0)
                return TK_OK;

        r = tk_sendn(s->sockfd, msg->header + aready_send_len, &need_send_len);
        msg->header_left_len -= need_send_len;
ilog("[send head]:%s", msg->header);

	return r;
}

void tk_recv_body_init(struct custom_socket *s)
{
        struct tk_connect *conn = (struct tk_connect*)s->conn_ptr;
	/* other infomation initialized by head init */

	conn->recving_head = 0;
	conn->recving_body = 1;
}

void tk_send_body_init(struct custom_socket *s)
{
        struct tk_connect *conn = (struct tk_connect*)s->conn_ptr;

	conn->sending_head = 0;
	conn->sending_body = 1;
}

/* @RETURN:    	1. TK_OK 
		2. TK_AGAIN 
		3. TK_ERROR 
		4. TK_DONE 
*/
int tk_recv_body(struct custom_socket *s) 
{
        int r = 0;
        int need_recv_len = 0;
        int aready_recv_len = 0;
        struct tk_connect *conn = (struct tk_connect*)s->conn_ptr;
        struct tk_message *msg = &conn->recv_msg;

        aready_recv_len = msg->body_len - msg->body_left_len;
        need_recv_len = msg->body_left_len;

        if (need_recv_len == 0)
                return TK_OK;

        /* @RETURN:        1. TK_OK 2. TK_AGAIN 3. TK_ERROR 4. TK_DONE */
        r = tk_recvn(s->sockfd, msg->body + aready_recv_len, &need_recv_len);
        msg->body_left_len -= need_recv_len;
//ilog("[recv body]:%s", msg->body);

        return r;		
}

/*
@RETURN:        1. TK_AGAIN
                2. TK_ERROR(errno)
                *3. TK_DONE(no use)*
                4. TK_OK
*/
int tk_send_body(struct custom_socket *s)
{
        int r = 0;
        int need_send_len = 0;
        int aready_send_len = 0;
        struct tk_connect *conn = (struct tk_connect*)s->conn_ptr;
        struct tk_message *msg = &conn->send_msg[conn->msg_start];

        need_send_len = msg->body_left_len;
        aready_send_len = msg->body_len - msg->body_left_len;

        if (need_send_len == 0)
                return TK_OK;

ilog("[send body]:%s", msg->body);
        /* @RETURN:        1. TK_AGAIN 2. TK_ERROR(errno) *3. TK_DONE(no use)* 4. TK_OK */
        r = tk_sendn(s->sockfd, msg->body + aready_send_len, &need_send_len);
        msg->body_left_len -= need_send_len;

	return r;
}

/***
@RETURN:        
	1. TK_AGAIN 
	2. TK_ERROR(errno) 
	3. TK_DONE(no use) 
	//4. TK_OK (head or body sent)
	4. TK_SEND_BODY_DONE(body sent)
	5. TK_NO_MORE_SEND_MSG (attention: other success status)
at most send one message
***/
int tk_do_send(struct custom_socket *s)
{
	int r = 0;
        struct tk_connect *conn = (struct tk_connect*)s->conn_ptr;

        if (conn->sending_head == 0 && conn->sending_body == 0) {
                tk_send_head_init(s);
        }
	
	if (conn->msg_start == conn->msg_end) {
		elog("no message send");
		return TK_NO_MORE_SEND_MSG;
	}

	if (conn->sending_head) {
		r = tk_send_head(s);
		if (r == TK_OK) {
			r = TK_SEND_HEAD_DONE; 
			tk_send_body_init(s);		
		}
		else {
			return r;
		}
	}
	if (conn->sending_body) {
		r = tk_send_body(s);
		if (r == TK_OK) {
			/* next message */
			conn->msg_start = (conn->msg_start + 1) % MAXMESSAGENUM;
			ilog("delete message start[%d] - end[%d]", conn->msg_start , conn->msg_end);

			/* no more message to send */
			if (conn->msg_start == conn->msg_end) {
				conn->sending_head = 0;
				conn->sending_body = 0;

				return TK_NO_MORE_SEND_MSG; 
			}
			else {
				r = TK_SEND_BODY_DONE;
			}
			
			return r;
		}
		else {
			return r;
		}
	}

	return TK_ERROR;
}

/* 
@RETURN:        
	//1. TK_OK (no use)
	2. TK_AGAIN 
	3. TK_ERROR 
	4. TK_DONE	(remote close)	
	5. TK_RECV_BODY_DONE
at most receive one message
*/
int tk_do_recv(struct custom_socket *s) 
{
	int r = 0;
        struct tk_connect *conn = (struct tk_connect*)s->conn_ptr;
	char tmp_buf[11];

	if (conn->recving_head == 0 && conn->recving_body == 0) {
		tk_recv_head_init(s);
	}

	if (conn->recving_head) {
		r = tk_recv_head(s);
		if (r == TK_OK) {
			conn->recv_msg.header[HEADERLEN] = '\0';
			conn->recv_msg.body_len = atoi(conn->recv_msg.header + MSGTYPELEN);
			conn->recv_msg.body_left_len = conn->recv_msg.body_len;
			memcpy(tmp_buf, conn->recv_msg.header, MSGTYPELEN);
			tmp_buf[MSGTYPELEN] = '\0';	
			conn->recv_msg.message_type = atoi(tmp_buf);
			conn->recv_msg.body_left_len = conn->recv_msg.body_len;
			ilog("receive message [%s] - [%d]", conn->recv_msg.header, conn->recv_msg.body_len);
			r = TK_RECV_HEAD_DONE;
			tk_recv_body_init(s);
		}
		else {
			return r;
		}
	}
	if (conn->recving_body) {
		r = tk_recv_body(s);
		if (r == TK_OK) {
			conn->recving_head = 0;
			conn->recving_body = 0;

			/* whole message received */
			r = TK_RECV_BODY_DONE;
			
			return r;
		}
		else {
			return r;	
		}
	}

	return TK_ERROR;
}

/**
@RETURN
	1. TK_NEED_ADD_W_EVENT
	2. TK_OK
**/ 
int tk_do_add_send_msg(struct custom_socket *s, struct tk_message *send_msg)
{
        struct tk_connect *conn = (struct tk_connect*)s->conn_ptr;
        struct tk_message *msg = NULL;
	int need_add_write_event = 0;

	if (conn->msg_start == conn->msg_end) {
		need_add_write_event = 1;
	}

        if ((conn->msg_end + 1) % MAXMESSAGENUM == conn->msg_start) {
                return TK_TOO_MUCH_SEND_MSG;
        }

        msg = &conn->send_msg[conn->msg_end];
        conn->msg_end = (conn->msg_end + 1) % MAXMESSAGENUM;
	ilog("add message start[%d] - end[%d]", conn->msg_start , conn->msg_end);

        /* copy msg info */
        memcpy(msg, send_msg, sizeof(struct tk_message));
        /* need to send head len */
        msg->header_left_len = HEADERLEN;

	if (need_add_write_event) {
		return TK_NEED_ADD_W_EVENT;
	}
	else {
		return TK_OK;
	}
}

#if 0
int tk_recv_file(FILE* save_to_file, struct custom_socket *s, int file_size)
{
	int r = 0;

	r = tk_recvn(int fd, char *buf, int *buf_len);
	
}
#endif

int tk_comm_error(struct epoll_env *env, struct custom_socket *s)
{
        struct tk_connect *conn = (struct tk_connect*)s->conn_ptr;
	void *event = s->event;

        if (is_active_read(event)) {
                (void)epoll_del_read_event(env, (void*)s);
                set_active_read(event, 0);
        }
        if (is_active_write(event)) {
                (void)epoll_del_write_event(env, (void*)s);
                set_active_write(event, 0);
        }

        set_active(event, 0);

        elog("ip[%s]-port[%d] error[%d]", s->addr.ipv4, s->addr.port, s->merrno);
        destory_tk_connect(env, conn);

        return TK_OK;
}

int tk_remote_comm_close(struct epoll_env *env, struct custom_socket *s)
{
        struct tk_connect *conn = (struct tk_connect*)s->conn_ptr;
	void *event = s->event;

        if (is_active_read(event)) {
                (void)epoll_del_read_event(env, (void*)s);
		set_active_read(event, 0);
        }
        if (is_active_write(event)) {
                (void)epoll_del_write_event(env, (void*)s);
                set_active_write(event, 0);
        }
        set_active(event, 0);

        elog("ip[%s]-port[%d] close", s->addr.ipv4, s->addr.port);
        destory_tk_connect(env, conn);

        return TK_OK;
}
